package com.ims.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ims.dao.*;
import com.ims.pojo.*;
import com.ims.service.UserService;
import com.ims.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import redis.clients.jedis.Jedis;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService, UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private LogPwdErrServiceImpl logPwdErrService;

    @Autowired
    private LogPwdErrMapper logPwdErrMapper;

    @Autowired
    private UserRoleCorMapper userRoleCorMapper;

    @Autowired
    private UserLogMapper userLogMapper;

    @Autowired
    private RoleMapper roleMapper;


    /**
     * 新增管理员用户
     * @param user
     * @return
     */
    @Override
    public Result<Integer> add(User user) {
        User one = userMapper.selectByUsername(user.getUsername());
        if (one != null) {
            return new Result(false, StatusCode.REPERROR, "该用户名已存在");
        }

        QueryWrapper<User> phoneWrapper = new QueryWrapper<>();
        phoneWrapper.eq("phone", user.getPhone());
        one = userMapper.selectOne(phoneWrapper);
        if (one != null) {
            return new Result(false, StatusCode.REPERROR, "手机号已经存在");
        }

        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setCreateTime(DateUtil.getFullTime());
        user.setSex("1");
        user.setStatus("1"); // 用户状态，正常
        int insert = userMapper.insert(user);
        int userId = 0;
        if (insert > 0) {
            userId = user.getUserId();
        }

        //在登录限制表（log_pwd_err）同步添加用户信息
        LogPwdErr logPwdErr = new LogPwdErr();
        logPwdErr.setUserName(user.getUsername());
        logPwdErr.setErrNum(0);
        logPwdErrMapper.insert(logPwdErr);

        return new Result<>(true, StatusCode.OK, "添加用户成功", userId);
    }

    /**
     * 查询所有用户
     * @return
     */
    @Override
    public Result<List<User>> findAll() {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getStatus, "1");
        wrapper.orderByAsc(User::getUsername);
        List<User> userList = userMapper.selectList(wrapper);
        return new Result<>(true, StatusCode.OK, "查询所有用户成功", userList);
    }

    /**
     * 分页查询
     * @param queryPageBean
     * @return
     */
    @Override
    public PageResult<User> findPage(QueryPageBean queryPageBean) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getStatus, '1');
        if (StringUtils.hasText(queryPageBean.getQueryString())) {
            wrapper.like(User::getUsername, queryPageBean.getQueryString()).or().like(User::getPhone, queryPageBean.getQueryString());
        }
        wrapper.orderByAsc(User::getUsername);
        Page<User> page = new Page<>(queryPageBean.getCurrentPage(), queryPageBean.getPageSize());
        page = userMapper.selectPage(page, wrapper);
        // 用户关联角色信息
        List<User> userList = page.getRecords();
        for (User user : userList) {
            LambdaQueryWrapper<UserRoleCor> urWrapper = new LambdaQueryWrapper<>();
            urWrapper.eq(UserRoleCor::getUserId, user.getUserId());
            UserRoleCor userRoleCor = userRoleCorMapper.selectOne(urWrapper);
            Role role = roleMapper.selectById(userRoleCor.getRoleId());
            user.setRoleId(role.getRoleId());
            user.setRoleName(role.getRoleName());
        }
        return new PageResult<>(page.getTotal(), page.getRecords());
    }

    /**
     * SpringSecurity 需要用
     * @param username
     * @return
     */
    public UserDetail loadUserByUsername(String username) {
        User user = userMapper.selectByUsername(username);
        // 若没查询到要抛出该异常，这样才能被Spring Security的错误处理器处理
        if (user == null) {
            throw new UsernameNotFoundException("没有找到该用户");
        }
        // 查询到了实体对象，那就返回自定义的UserDetail对象
        return new UserDetail(user, Collections.emptyList());
    }

    /**
     * 用户登录
     * @param username
     * @param password
     * @return
     */
    @Override
    public Result login(String username, String password, HttpServletRequest request, HttpServletResponse response) {
        // 1.判断用户名和密码是否为空，为空返回错误
        if (!StringUtils.hasText(username) || !StringUtils.hasText(password)) {
            return new Result(false, StatusCode.LOGINERROR, "用户名或密码为空");
        }

        // 2.根据用户名查询出用户实体对象
        User user = userMapper.selectByUsername(username);
        // 若没有查到用户，返回错误
        if (user == null) {
            return new Result(false, StatusCode.LOGINERROR, "用户不存在");
        }

        //判定条件  失败登录的次数 < 5 或者 距离上次登录已经过了30分钟
        if (logPwdErrService.logErrValid(user, request) || logPwdErrService.checkTime(user)) {
            // 密码校验失败，返回错误
            if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
                //每次登录失败，失败的次数+1
                logPwdErrService.addErrorNum(user);
                return new Result(false, StatusCode.LOGINERROR, "用户名或密码错误");
            }

            // 3.校验通过，登录成功
            // 更新用户登录时间
            user.setLoginTime(DateUtil.getFullTime());
            userMapper.updateById(user);

            // 记录用户日志
            UserLog userLog = new UserLog();
            userLog.setUserId(user.getUserId());
            userLog.setUsername(user.getUsername());
            userLog.setOperation(LogUtil.successLogin);
            userLog.setEventTime(DateUtil.getFullTime());
            userLog.setIpAddress(RequestUtil.getIpAddress(request));
            userLogMapper.insert(userLog);

            // 登录成功，即将 errNum 置为 0
            logPwdErrService.clearErrorNum(user);

            UserVO userVO = new UserVO();
            userVO.setId(user.getUserId());
            userVO.setUsername(user.getUsername());
            // 生成令牌，并返回令牌
            // 生成JWT，将用户名数据存入其中
            String accessToken = jwtUtil.generateAccessToken(user.getUsername());
            String refreshToken = jwtUtil.generateRefreshToken(user.getUsername());
            response.setHeader("Authorization", accessToken);
            saveCookie(accessToken);

            userVO.setAccessToken(accessToken);
            userVO.setRefreshToken(refreshToken);
            Jedis jedis = new Jedis(RedisUtil.host, RedisUtil.port);
            jedis.set("accessToken", accessToken);
            jedis.set("refreshToken", refreshToken);
            jedis.set("username" + user.getUserId(), username);
            jedis.close();
            return new Result(true, StatusCode.OK, "登录成功", userVO);
        } else {
            return new Result(false, StatusCode.LOGINERROR, "密码错误次数过多，请30分钟后再试");
        }
    }

    /**
     * 退出登录
     * @param userId
     * @return
     */
    @Override
    public Result logout(Integer userId) {
        User user = userMapper.selectById(userId);
        user.setLogoutTime(DateUtil.getFullTime());
        // 修改用户退出时间
        userMapper.updateById(user);
        // 记录用户日志
        UserLog userLog = new UserLog();
        userLog.setUserId(user.getUserId());
        userLog.setUsername(user.getUsername());
        userLog.setOperation(LogUtil.successLogout);
        userLog.setEventTime(DateUtil.getFullTime());
        userLogMapper.insert(userLog);
        Jedis jedis = new Jedis(RedisUtil.host, RedisUtil.port);
        jedis.del("username" + userId);
        jedis.del("token");
        jedis.close();
        return new Result<>(true, StatusCode.OK, "用户" + user.getUsername() + "退出成功");
    }

    /**
     * 删除用户，同时删除用户角色表中的信息
     * @param userId
     * @return
     */
    @Override
    @Transactional
    public Result deleteById(Integer userId) {
        User user = userMapper.selectById(userId);
        LambdaQueryWrapper<UserRoleCor> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserRoleCor::getUserId, userId);
        List<UserRoleCor> userRoleCorList = userRoleCorMapper.selectList(wrapper);
        for (UserRoleCor userRoleCor : userRoleCorList) {
            // 该角色为超级管理员
            if (userRoleCor.getRoleId() == 1) {
                return new Result<>(false, StatusCode.ACCESSERROR, "不允许删除超级管理员！");
            }
        }
        int deleteUser = userMapper.deleteById(userId);
        if (deleteUser > 0) {
            //同时删除table_user_role表中对应的记录
            int deleteUserRole = userRoleCorMapper.delete(wrapper);

            //同时删除log_pwd_err表中对应的记录
            LambdaQueryWrapper<LogPwdErr> logPwdErrWrapper = new LambdaQueryWrapper<>();
            logPwdErrWrapper.eq(LogPwdErr::getUserName, user.getUsername());
            int deleteLogPwdErr = logPwdErrMapper.delete(logPwdErrWrapper);

            if (deleteUserRole > 0 && deleteLogPwdErr > 0) {
                return new Result<>(true, StatusCode.OK, "删除成功");
            }
        }

        return new Result<>(false, StatusCode.ERROR, "删除失败");
    }

    /**
     * 更新用户
     * @param user
     * @return
     */
    @Override
    public Result updateUser(User user) {
        User one = userMapper.selectByUsername(user.getUsername());
        // 如果该用户名已存在，且不为当前用户
        if (one != null && one.getUserId() != user.getUserId()) {
            return new Result(false, StatusCode.REPERROR, "该用户名已存在");
        }

        QueryWrapper<User> phoneWrapper = new QueryWrapper<>();
        phoneWrapper.eq("phone", user.getPhone());
        one = userMapper.selectOne(phoneWrapper);
        // 如果该手机号已存在，且不为当前用户
        if (one != null && one.getUserId() != user.getUserId()) {
            return new Result(false, StatusCode.REPERROR, "手机号已经存在");
        }
        int updateFlag = userMapper.updateById(user);
        if (updateFlag > 0) {
            return new Result<>(true, StatusCode.OK, "更新成功");
        } else {
            return new Result<>(false, StatusCode.ERROR, "更新失败");
        }
    }

    /**
     * 将token存入cookie
     * @param token
     */
    private void saveCookie(String token) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        CookieUtil.addCookie(response, "localhost", "/", "Authorization", token, -1, false);
    }
}
